import { Graph, Addon, FunctionExt, Shape } from "@antv/x6";
import "./shape";
import { customPorts } from "./ports";
import { getImg } from "../../../utils";
import graphData from "./data/data-custom-3.js";
const insertCss = require("insert-css");

insertCss(`
  @keyframes ant-line {
    to {
        stroke-dashoffset: -1000
    }
  }
`);

export default class FlowGraph {
  static graph = null;
  static stencil = null;

  /**
   * 初始化方法
   * @param {*} dom 画板容器
   * @param {*} width 容器宽度
   * @param {*} height 容器高度
   * @param {*} flag 默认为true，传入false只实例化画板
   * @returns
   */
  static init(dom, width = 1200, height = 900, flag = true) {
    // 初始化 流程图画板
    this.graph = new Graph({
      // background: {
      //   color: '#e5e5e5' // 设置画布背景颜色
      // },
      container: dom,
      width: width,
      height: height,
      autoResize: true,
      grid: {
        size: 10,
        visible: true,
        type: "doubleMesh",
        args: [
          {
            color: "#cccccc",
            thickness: 1,
          },
          {
            color: "#5F95FF",
            thickness: 1,
            factor: 4,
          },
        ],
      },
      scroller: {
        enabled: false,
        pageVisible: false,
        pageBreak: false,
        pannable: false,
      },
      // 开启画布缩放
      mousewheel: {
        enabled: true,
        modifiers: ["ctrl", "meta"],
        minScale: 0.5,
        maxScale: 2,
      },
      interacting: {
        nodeMovable: true, //节点是否可以被移动。
        edgeMovable: true, //边是否可以被移动。
        edgeLabelMovable: true, //边的标签是否可以被移动。
        arrowheadMovable: true, //边的起始/终止箭头是否可以被移动
        vertexMovable: true, //边的路径点是否可以被移动。
        vertexAddable: true, //是否可以添加边的路径点。
        vertexDeletable: true, //边的路径点是否可以被删除。
      },
      connecting: {
        anchor: "center",
        connectionPoint: "anchor",
        allowBlank: true,
        highlight: true,
        snap: true, // 是否自动吸附
        allowMulti: true, // 是否允许在相同的起始节点和终止之间创建多条边
        allowNode: false, // 是否允许边链接到节点（非节点上的链接桩）
        allowBlank: false, // 是否允许连接到空白点
        allowLoop: false, // 是否允许创建循环连线，即边的起始节点和终止节点为同一节点，
        allowEdge: false, // 是否允许边链接到另一个边
        highlight: true, // 拖动边时，是否高亮显示所有可用的连接桩或节点
        connectionPoint: "anchor", // 指定连接点
        anchor: "center", // 指定被连接的节点的锚点
        createEdge() {
          // X6 的 Shape 命名空间中内置 Edge、DoubleEdge、ShadowEdge 三种边
          return new Shape.Edge({
            attrs: {
              // line: {
              //   // stroke: '#5F95FF',
              //   // strokeWidth: 4,
              //   // targetMarker: {
              //   //   name: 'classic',
              //   //   size: 8,
              //   // },
              //   stroke: '#1890ff',
              //   strokeDasharray: 5,
              //   targetMarker: null,//block classic diamond cross async path circle circlePlus ellipse
              //   style: {
              //     animation: 'ant-line 30s infinite linear',
              //   },
              // },
              line: {
                strokeWidth: 1,
                stroke: "#5F95FF",
                strokeDasharray: 0,
                style: {
                  animation: "ant-line 0s infinite linear",
                },
                targetMarker: null, // 去掉箭头
              },
            },
            router: {
              name: "metro",
              args: {
                offset: 32,
                direction: "H",
              },
            },
          });
        },
        validateConnection({
          sourceView,
          targetView,
          sourceMagnet,
          targetMagnet,
        }) {
          if (sourceView === targetView) {
            return false;
          }
          if (!sourceMagnet) {
            return false;
          }
          if (!targetMagnet) {
            return false;
          }
          return true;
        },
      },
      highlighting: {
        magnetAvailable: {
          name: "stroke",
          args: {
            padding: 4,
            attrs: {
              strokeWidth: 4,
              stroke: "rgba(223,234,255)",
            },
          },
        },
      },
      // 开启拖拽平移（防止冲突，按下修饰键并点击鼠标才能触发画布拖拽）
      panning: {
        enabled: true,
        modifiers: "shift",
      },
      resizing: true,
      rotating: true,
      selecting: {
        enabled: true,
        multiple: true,
        rubberband: true,
        movable: true,
        showNodeSelectionBox: true,
      },
      snapline: true,
      history: true,
      clipboard: {
        enabled: true,
      },
      keyboard: {
        enabled: true,
      },
      embedding: {
        enabled: true,
        front: true, // 确保子节点在最前面，不被 group 遮挡
        findParent({ node }) {
          const bbox = node.getBBox();
          return this.getNodes().filter((node) => {
            const data = node.getData();
            if (data && data.parent) {
              const targetBBox = node.getBBox();
              return bbox.isIntersectWithRect(targetBBox);
            }
            return false;
          });
        },
      },
    });
    if (!flag) {
      // this.graph.centerContent()
      this.graph.hideGrid(); // 返显渲染的时候 隐藏网格
      return this.graph;
    }
    this.initStencil();
    this.initShape();
    this.initGraphShape();
    this.initEvent();
    return this.graph;
  }
  // 初始化根节点
  static initStencil() {
    this.stencil = new Addon.Stencil({
      target: this.graph,
      stencilGraphWidth: 280,
      search: { rect: true },
      collapsable: true,
      groups: [
        {
          name: "basic",
          title: "基础节点",
          graphHeight: 230,
        },
        {
          name: "custom-image",
          title: "系统设计图",
          graphHeight: 600,
        },
        {
          name: "combination",
          title: "组合节点",
          layoutOptions: {
            columns: 1,
            marginX: 60,
          },
          graphHeight: 260,
        },
        {
          name: "group",
          title: "节点组",
          graphHeight: 450,
          layoutOptions: {
            columns: 1,
            marginX: 60,
          },
        },
      ],
    });
    const stencilContainer = document.querySelector("#stencil");
    stencilContainer?.appendChild(this.stencil.container);
  }
  // 初始化具体每个根节点下不同类型节点
  static initShape() {
    const { graph } = this;
    // 基础节点
    const r1 = graph.createNode({
      shape: "flow-chart-rect",
      attrs: {
        body: {
          rx: 24,
          ry: 24,
        },
        text: {
          text: "起始节点",
        },
      },
    });
    const r2 = graph.createNode({
      shape: "flow-chart-rect",
      attrs: {
        text: {
          text: "流程节点",
        },
        body: {
          rx: 6,
          ry: 6,
        },
      },
    });
    const r3 = graph.createNode({
      shape: "flow-chart-rect",
      width: 52,
      height: 52,
      angle: 45,
      attrs: {
        "edit-text": {
          style: {
            transform: "rotate(-45deg)",
          },
        },
        text: {
          text: "判断节点",
          transform: "rotate(-45deg)",
        },
      },
      ports: {
        groups: {
          top: {
            position: {
              name: "top",
              args: {
                dx: -26,
              },
            },
          },
          right: {
            position: {
              name: "right",
              args: {
                dy: -26,
              },
            },
          },
          bottom: {
            position: {
              name: "bottom",
              args: {
                dx: 26,
              },
            },
          },
          left: {
            position: {
              name: "left",
              args: {
                dy: 26,
              },
            },
          },
        },
      },
    });
    const r4 = graph.createNode({
      shape: "flow-chart-rect",
      width: 70,
      height: 70,
      attrs: {
        body: {
          rx: 35,
          ry: 35,
        },
        text: {
          text: "链接节点",
        },
      },
    });
    // const r5 = graph.createNode({
    //   shape: "flow-chart-image-node",
    //   height: 80,
    //   width: 80,
    //   markup: [
    //     { tagName: "image", selector: "image" },
    //     { tagName: "rect", selector: "body" },
    //     { tagName: "text", selector: "label" },
    //   ],
    //   attrs: {
    //     image: {
    //       ref: "body",
    //       refWidth: "100%",
    //       refHeight: "100%",
    //       "xlink:href":
    //         "https://ts3.tc.mm.bing.net/th/id/OIP-C.g9UbVfyVZX-SfD09JcYr5QHaEK?rs=1&pid=ImgDetMain",
    //       zIndex: 0, // ⬅ 图片在底
    //     },
    //     body: {
    //       fill: "transparent",
    //       stroke: "#000",
    //       zIndex: 1,
    //     },
    //     label: {
    //       text: "1234123",
    //       zIndex: 2, // ⬅ 文字最上层
    //     },
    //   },
    // });
    // 组合节点
    const c1 = graph.createNode({
      shape: "flow-chart-image-rect",
    });
    const c2 = graph.createNode({
      shape: "flow-chart-title-rect",
    });
    const c3 = graph.createNode({
      shape: "flow-chart-animate-text",
    });
    // 节点组
    const g1 = graph.createNode({
      shape: "groupNode",
      attrs: {
        text: {
          text: "Group Name",
        },
      },
      data: {
        parent: true,
      },
    });
    const g2 = graph.createNode({
      shape: "groupNodeSimple",
      size: {
        width: 200,
        height: 80,
      },
      attrs: {
        title: {
          text: "分组标题",
        },
        text: {
          text: "这里是分组的说明",
        },
      },
      data: {
        parent: true,
      },
    });
    const g3 = graph.createNode({
      shape: "groupNodeSimpleNoHead",
      attrs: {
        text: {
          text: "Group Name",
        },
      },
      data: {
        parent: true,
      },
    });
    const g4 = graph.createNode({
      shape: "groupNodeCollapsibleNoHead",
      size: {
        width: 200,
        height: 80,
      },
      attrs: {
        text: {
          text: "这里是分组的说明",
        },
      },
      data: {
        parent: true,
      },
    });
    const g5 = graph.createNode({
      shape: "groupNodeWithHeaderImage",
      size: {
        width: 200,
        height: 80,
      },
      attrs: {
        text: {
          text: "这里是分组的说明",
        },
      },
      data: {
        parent: true,
      },
    });
    // 系统设计图
    const imgs = [
      {
        image: getImg("ldb.png"),
      },
      {
        image: getImg("wft1.png"),
      },
      {
        image: getImg("wft2.png"),
      },
      {
        image: getImg("wft3.png"),
      },
      {
        image: getImg("wft4.png"),
      },
      {
        image: getImg("wft5.png"),
      },
      {
        image: getImg("lqt.png"),
      },
      {
        image: getImg("lqb-o.png"),
      },
      {
        image: getImg("ldb-o.png"),
      },
      {
        image: getImg("bh.png"),
      },
      {
        image: getImg("f1.png"),
      },
      {
        image: getImg("f2.png"),
      },
      {
        image: getImg("f3.png"),
      },
    ];
    const imgNodes = imgs.map((item) => {
      return graph.createNode({
        // shape: 'flow-chart-image-rect-custom',
        // attrs: {
        //   image: {
        //     'xlink:href': item.image,
        //   }
        // }
        shape: "image", //可选值：Rect Circle Ellipse Polygon Polyline Path Image HTML TextBlock BorderedImage EmbeddedImage InscribedImage Cylinder
        imageUrl: item.image,
        attrs: {
          image: {
            // fill: 'yellow',
          },
        },
        width: 52,
        height: 52,
        ports: { ...customPorts },
      });
    });
    this.stencil.load([r1, r2, r3, r4], "basic");
    this.stencil.load(imgNodes, "custom-image");
    this.stencil.load([c1, c2, c3], "combination");
    this.stencil.load([g1, g2, g3, g4, g5], "group");
  }

  // 根据json渲染节点和边
  static initGraphShape(gd = graphData) {
    this.graph.fromJSON(gd);
    this.graph.getNodes().forEach((node) => {
      const parentId = node.getParentId?.();
      if (parentId) {
        const parent = this.graph.getCellById(parentId);
        if (parent) {
          parent.embed(node);
        }
      }
    });
  }

  // 连接桩显示时机
  static showPorts(ports, show) {
    for (let i = 0, len = ports.length; i < len; i = i + 1) {
      ports[i].style.visibility = show ? "visible" : "hidden";
    }
  }

  // 事件相关
  static initEvent() {
    const { graph } = this;
    const container = document.getElementById("container");
    // 右键编辑文本
    // graph.on("node:contextmenu", ({ cell, view }) => {
    //   console.log(view.container);
    //   const oldText = cell.attr("text/text");
    //   cell.attr("text/style/display", "none");
    //   const elem = view.container.querySelector(".x6-edit-text");
    //   if (elem) {
    //     elem.innerText = oldText;
    //     elem.focus();
    //   }
    //   const onBlur = () => {
    //     cell.attr("text/text", elem.innerText);
    //     cell.attr("text/style/display", "inline-block");
    //   };
    //   if (elem) {
    //     elem.addEventListener("blur", () => {
    //       onBlur();
    //       elem.removeEventListener("blur", onBlur);
    //     });
    //   }
    // });
    // 鼠标移入 显示连接桩
    graph.on(
      "node:mouseenter",
      FunctionExt.debounce(() => {
        const ports = container.querySelectorAll(".x6-port-body");
        this.showPorts(ports, true);
      }),
      500
    );
    graph.on("node:embedded", ({ node }) => {
      // 设置交互样式，让用户知道可以拖动
      node.setAttrs({
        body: {
          cursor: "move",
        },
      });

      // 如果你之前通过 graph.interacting 禁用了交互，可以动态放开交互
      graph.options.interacting = (cellView) => {
        const cell = cellView.cell;
        if (cell.getData()?.locked) {
          return { nodeMovable: false };
        }
        return true;
      };
    });
    // 鼠标移出 隐藏连接桩
    graph.on("node:mouseleave", () => {
      const ports = container.querySelectorAll(".x6-port-body");
      this.showPorts(ports, false);
    });

    graph.on("node:collapse", ({ node, e }) => {
      e.stopPropagation();
      node.toggleCollapse();
      const collapsed = node.isCollapsed();
      const cells = node.getDescendants();
      cells.forEach((n) => {
        if (collapsed) {
          n.hide();
        } else {
          n.show();
        }
      });
    });
    // backspace
    graph.bindKey("delete", () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.removeCells(cells);
      }
    });
    // 鼠标动态添加/删除小工具。
    graph.on("edge:mouseenter", ({ cell }) => {
      /**
       * EdgeTool
       * vertices 路径点工具，在路径点位置渲染一个小圆点，拖动小圆点修改路径点位置，双击小圆点删除路径点，在边上单击添加路径点。
       * segments 线段工具。在边的每条线段的中心渲染一个工具条，可以拖动工具条调整线段两端的路径点的位置。
       * boundary 根据边的包围盒渲染一个包围边的矩形。注意，该工具仅仅渲染一个矩形，不带任何交互。
       * button 在指定位置处渲染一个按钮，支持自定义按钮的点击交互。
       * button-remove 在指定的位置处，渲染一个删除按钮，点击时删除对应的边。
       * source-arrowhead-和-target-arrowhead 在边的起点或终点渲染一个图形(默认是箭头)，拖动该图形来修改边的起点或终点。
       * edge-editor 提供边上文本编辑功能。
       */
      cell.addTools([
        {
          name: "vertices",
          args: {
            attrs: { fill: "#007acc" },
            // 移动路径点过程中的吸附半径。当路径点与邻近的路径点的某个坐标 (x, y) 距离在半径范围内时，将当前路径点的对应坐标 (x, y) 吸附到邻居路径的路径点。
            snapRadius: 20,
            // 在边上按下鼠标时，是否可以添加新的路径点。
            addable: true,
            // 是否可以通过双击移除路径点。
            removable: true,
            // 是否自动移除冗余的路径点。
            removeRedundancies: true,
            // 是否阻止工具上的鼠标事件冒泡到边视图上。阻止后鼠标与工具交互时将不会触发边的 mousedown、mousemove 和 mouseup 事件。
            stopPropagation: false,
          },
        },
      ]);
    });
    graph.on("edge:mouseleave", ({ cell }) => {
      cell.removeTools();
    });
  }
}
